home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
edit
/
elv18src.zip
/
cmd2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-02
|
18KB
|
991 lines
/* cmd2.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains some of the commands - mostly ones that change text */
#ifdef AIX
# define _XOPEN_SOURCE
# include <sys/mode.h>
# include <sys/stat.h>
# undef _XOPEN_SOURCE
#endif
#include "config.h"
#include "ctype.h"
#include "vi.h"
#include "regexp.h"
#if TOS
# include <stat.h>
#else
# if OSK
# include "osk.h"
# else
# if AMIGA
# include "amistat.h"
# else
# include <sys/stat.h>
# endif
# endif
#endif
/*ARGSUSED*/
void cmd_substitute(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra; /* rest of the command line */
{
char *line; /* a line from the file */
regexp *re; /* the compiled search expression */
char *subst; /* the substitution string */
char *opt; /* substitution options */
long l; /* a line number */
char *s, *d; /* used during subtitutions */
char *conf; /* used during confirmation */
long chline; /* # of lines changed */
long chsub; /* # of substitutions made */
static optp; /* boolean option: print when done? */
static optg; /* boolean option: substitute globally in line? */
static optc; /* boolean option: confirm before subst? */
#ifndef CRUNCH
long oldnlines;
#endif
/* for now, assume this will fail */
rptlines = -1L;
if (cmd == CMD_SUBAGAIN)
{
#ifndef NO_MAGIC
if (*o_magic)
subst = "~";
else
#endif
subst = "\\~";
re = regcomp("");
/* if visual "&", then turn off the "p" and "c" options */
if (bang)
{
optp = optc = FALSE;
}
}
else /* CMD_SUBSTITUTE */
{
/* make sure we got a search pattern */
if (!*extra)
{
msg("Usage: s/regular expression/new text/");
return;
}
/* parse & compile the search pattern */
subst = parseptrn(extra);
re = regcomp(extra + 1);
}
/* abort if RE error -- error message already given by regcomp() */
if (!re)
{
return;
}
if (cmd == CMD_SUBSTITUTE)
{
/* parse the substitution string & find the option string */
for (opt = subst; *opt && *opt != *extra; opt++)
{
if (*opt == '\\' && opt[1])
{
opt++;
}
}
if (*opt)
{
*opt++ = '\0';
}
/* analyse the option string */
if (!*o_edcompatible)
{
optp = optg = optc = FALSE;
}
while (*opt)
{
switch (*opt++)
{
case 'p': optp = !optp; break;
case 'g': optg = !optg; break;
case 'c': optc = !optc; break;
case ' ':
case '\t': break;
default:
msg("Subst options are p, c, and g -- not %c", opt[-1]);
return;
}
}
}
/* if "c" or "p" flag was given, and we're in visual mode, then NEWLINE */
if ((optc || optp) && mode == MODE_VI)
{
addch('\n');
exrefresh();
}
ChangeText
{
/* reset the change counters */
chline = chsub = 0L;
/* for each selected line */
for (l = markline(frommark); l <= markline(tomark); l++)
{
/* fetch the line */
line = fetchline(l);
/* if it contains the search pattern... */
if (regexec(re, line, TRUE))
{
/* increment the line change counter */
chline++;
/* initialize the pointers */
s = line;
d = tmpblk.c;
/* do once or globally ... */
do
{
#ifndef CRUNCH
/* confirm, if necessary */
if (optc)
{
for (conf = line; conf < re->startp[0]; conf++)
addch(*conf);
standout();
for ( ; conf < re->endp[0]; conf++)
addch(*conf);
standend();
for (; *conf; conf++)
addch(*conf);
addch('\n');
exrefresh();
if (getkey(0) != 'y')
{
/* copy accross the original chars */
while (s < re->endp[0])
*d++ = *s++;
/* skip to next match on this line, if any */
goto Continue;
}
}
#endif /* not CRUNCH */
/* increment the substitution change counter */
chsub++;
/* copy stuff from before the match */
while (s < re->startp[0])
{
*d++ = *s++;
}
/* substitute for the matched part */
regsub(re, subst, d);
s = re->endp[0];
d += strlen(d);
Continue:
/* if this regexp could conceivably match
* a zero-length string, then require at
* least 1 unmatched character between
* matches.
*/
if (re->minlen == 0)
{
if (!*s)
break;
*d++ = *s++;
}
} while (optg && regexec(re, s, FALSE));
/* copy stuff from after the match */
while (*d++ = *s++) /* yes, ASSIGNMENT! */
{
}
#ifndef CRUNCH
/* NOTE: since the substitution text is allowed to have ^Ms which are
* translated into newlines, it is possible that the number of lines
* in the file will increase after each line has been substituted.
* we need to adjust for this.
*/
oldnlines = nlines;
#endif
/* replace the old version of the line with the new */
d[-1] = '\n';
d[0] = '\0';
change(MARK_AT_LINE(l), MARK_AT_LINE(l + 1), tmpblk.c);
#ifndef CRUNCH
l += nlines - oldnlines;
tomark += MARK_AT_LINE(nlines - oldnlines);
#endif
/* if supposed to print it, do so */
if (optp)
{
addstr(tmpblk.c);
exrefresh();
}
/* move the cursor to that line */
cursor = MARK_AT_LINE(l);
}
}
}
/* free the regexp */
_free_(re);
/* if done from within a ":g" command, then finish silently */
if (doingglobal)
{
rptlines = chline;
rptlabel = "changed";
return;
}
/* Reporting */
if (chsub == 0)
{
msg("Substitution failed");
}
else if (chline >= *o_report)
{
msg("%ld substitutions on %ld lines", chsub, chline);
}
rptlines = 0L;
}
/*ARGSUSED*/
void cmd_delete(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
MARK curs2; /* an altered form of the cursor */
/* choose your cut buffer */
if (*extra == '"')
{
extra++;
}
if (*extra)
{
cutname(*extra);
}
/* make sure we're talking about whole lines here */
frommark = frommark & ~(BLKSIZE - 1);
tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
/* yank the lines */
cut(frommark, tomark);
/* if CMD_DELETE then delete the lines */
if (cmd != CMD_YANK)
{
curs2 = cursor;
ChangeText
{
/* delete the lines */
delete(frommark, tomark);
}
if (curs2 > tomark)
{
cursor = curs2 - tomark + frommark;
}
else if (curs2 > frommark)
{
cursor = frommark;
}
}
}
/*ARGSUSED*/
void cmd_append(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
long l; /* line counter */
#ifndef CRUNCH
/* if '!' then toggle auto-indent */
if (bang)
{
*o_autoindent = !*o_autoindent;
}
#endif
ChangeText
{
/* if we're doing a change, delete the old version */
if (cmd == CMD_CHANGE)
{
/* delete 'em */
cmd_delete(frommark, tomark, cmd, bang, extra);
}
/* new lines start at the frommark line, or after it */
l = markline(frommark);
if (cmd == CMD_APPEND)
{
l++;
}
/* get lines until no more lines, or "." line, and insert them */
while (vgets('\0', tmpblk.c, BLKSIZE) >= 0)
{
addch('\n');
if (!strcmp(tmpblk.c, "."))
{
break;
}
strcat(tmpblk.c, "\n");
add(MARK_AT_LINE(l), tmpblk.c);
l++;
}
}
/* on the odd chance that we're calling this from vi mode ... */
redraw(MARK_UNSET, FALSE);
}
/*ARGSUSED*/
void cmd_put(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
/* choose your cut buffer */
if (*extra == '"')
{
extra++;
}
if (*extra)
{
cutname(*extra);
}
/* paste it */
ChangeText
{
cursor = paste(frommark, TRUE, FALSE);
}
}
/*ARGSUSED*/
void cmd_join(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
long l;
char *scan;
int len; /* length of the new line */
/* if only one line is specified, assume the following one joins too */
if (markline(frommark) == nlines)
{
msg("Nothing to join with this line");
return;
}
if (markline(frommark) == markline(tomark))
{
tomark += BLKSIZE;
}
/* get the first line */
l = markline(frommark);
strcpy(tmpblk.c, fetchline(l));
len = strlen(tmpblk.c);
/* build the l